package risk.control.project.utils.vaild;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

public class IdCardValidator {

    // 省份代码
    private static final Map<String, String> PROVINCE_CODES = new HashMap<>();

    // 每位加权因子(18位身份证)
    private static final int[] WEIGHT_FACTORS = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};

    // 校验码对应值(18位身份证)
    private static final char[] CHECK_CODES = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};

    // 初始化省份代码
    static {
        PROVINCE_CODES.put("11", "北京");
        PROVINCE_CODES.put("12", "天津");
        PROVINCE_CODES.put("13", "河北");
        PROVINCE_CODES.put("14", "山西");
        PROVINCE_CODES.put("15", "内蒙古");
        PROVINCE_CODES.put("21", "辽宁");
        PROVINCE_CODES.put("22", "吉林");
        PROVINCE_CODES.put("23", "黑龙江");
        PROVINCE_CODES.put("31", "上海");
        PROVINCE_CODES.put("32", "江苏");
        PROVINCE_CODES.put("33", "浙江");
        PROVINCE_CODES.put("34", "安徽");
        PROVINCE_CODES.put("35", "福建");
        PROVINCE_CODES.put("36", "江西");
        PROVINCE_CODES.put("37", "山东");
        PROVINCE_CODES.put("41", "河南");
        PROVINCE_CODES.put("42", "湖北");
        PROVINCE_CODES.put("43", "湖南");
        PROVINCE_CODES.put("44", "广东");
        PROVINCE_CODES.put("45", "广西");
        PROVINCE_CODES.put("46", "海南");
        PROVINCE_CODES.put("50", "重庆");
        PROVINCE_CODES.put("51", "四川");
        PROVINCE_CODES.put("52", "贵州");
        PROVINCE_CODES.put("53", "云南");
        PROVINCE_CODES.put("54", "西藏");
        PROVINCE_CODES.put("61", "陕西");
        PROVINCE_CODES.put("62", "甘肃");
        PROVINCE_CODES.put("63", "青海");
        PROVINCE_CODES.put("64", "宁夏");
        PROVINCE_CODES.put("65", "新疆");
        PROVINCE_CODES.put("71", "台湾");
        PROVINCE_CODES.put("81", "香港");
        PROVINCE_CODES.put("82", "澳门");
        PROVINCE_CODES.put("91", "国外");
    }

    /**
     * 验证身份证是否合法
     *
     * @param idCard 身份证号码
     * @return 合法返回true，否则返回false
     */
    public static boolean isValid(String idCard) {
        if (idCard == null || idCard.length() != 15 && idCard.length() != 18) {
            return false;
        }

        // 15位身份证
        if (idCard.length() == 15) {
            return validate15DigitIdCard(idCard);
        }

        // 18位身份证
        return validate18DigitIdCard(idCard);
    }

    /**
     * 验证15位身份证
     *
     * @param idCard 身份证号码
     * @return 合法返回true，否则返回false
     */
    private static boolean validate15DigitIdCard(String idCard) {
        // 校验省份代码
        String provinceCode = idCard.substring(0, 2);
        if (!PROVINCE_CODES.containsKey(provinceCode)) {
            return false;
        }

        // 校验出生日期
        String birthDate = "19" + idCard.substring(6, 12);
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        dateFormat.setLenient(false); // 严格模式

        try {
            Date date = dateFormat.parse(birthDate);
            // 检查日期是否合理(不能超过当前日期)
            return !date.after(new Date());
        } catch (ParseException e) {
            return false;
        }
    }

    /**
     * 验证18位身份证
     *
     * @param idCard 身份证号码
     * @return 合法返回true，否则返回false
     */
    private static boolean validate18DigitIdCard(String idCard) {
        // 校验前17位是否为数字
        String first17Digits = idCard.substring(0, 17);
        if (!Pattern.matches("^\\d+$", first17Digits)) {
            return false;
        }

        // 校验省份代码
        String provinceCode = idCard.substring(0, 2);
        if (!PROVINCE_CODES.containsKey(provinceCode)) {
            return false;
        }

        // 校验出生日期
        String birthDate = idCard.substring(6, 14);
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        dateFormat.setLenient(false); // 严格模式

        try {
            Date date = dateFormat.parse(birthDate);
            // 检查日期是否合理(不能超过当前日期)
            if (date.after(new Date())) {
                return false;
            }
        } catch (ParseException e) {
            return false;
        }

        // 计算校验码
        char checkCode = calculateCheckCode(first17Digits);
        return Character.toUpperCase(idCard.charAt(17)) == checkCode;
    }

    /**
     * 计算18位身份证的校验码
     *
     * @param first17Digits 身份证前17位
     * @return 校验码
     */
    private static char calculateCheckCode(String first17Digits) {
        int sum = 0;
        for (int i = 0; i < 17; i++) {
            int digit = Character.getNumericValue(first17Digits.charAt(i));
            sum += digit * WEIGHT_FACTORS[i];
        }
        return CHECK_CODES[sum % 11];
    }

    /**
     * 获取身份证信息
     *
     * @param idCard 身份证号码
     * @return 包含省份、出生日期和性别的Map，如果身份证不合法返回null
     */
    public static Map<String, String> getIdCardInfo(String idCard) {
        if (!isValid(idCard)) {
            return null;
        }

        Map<String, String> info = new HashMap<>();

        // 获取省份
        String provinceCode = idCard.substring(0, 2);
        info.put("province", PROVINCE_CODES.get(provinceCode));

        // 获取出生日期
        String birthDateStr = idCard.length() == 15 ? "19" + idCard.substring(6, 12) : idCard.substring(6, 14);
        info.put("birthDate", birthDateStr);

        // 获取性别(15位身份证取最后一位，18位身份证取倒数第二位)
        int genderDigit = idCard.length() == 15 ? Character.getNumericValue(idCard.charAt(14)) : Character.getNumericValue(idCard.charAt(16));
        info.put("gender", genderDigit % 2 == 1 ? "男" : "女");

        return info;
    }
}
